# coding:utf-8
import base64
import json
import os
import time
from PyQt6.QtGui import QImage, QPixmap
from PyQt6 import QtWidgets
from PyQt6.QtCore import (
    Qt, QTimer
)
from PyQt6.QtWidgets import (
    QFileDialog
)
import numpy as np
import sys
import threading
import cv2
import openai
import sim
import re
import open3d as o3d
import wdy_ControlBoarb_qt6, model
from dobot_api import DobotApiDashboard, DobotApi, DobotApiMove
from wdy_camera import RealSenseThread, CameraInfoDialog
from wdy_vrep import CoppeliasimClass
from wdy_key import *

class MyWindow(QtWidgets.QMainWindow, wdy_ControlBoarb_qt6.Ui_mainWindow):
    def __init__(self, temp_path):
        # 修改初始化方式
        QtWidgets.QMainWindow.__init__(self)  # 直接调用父类的__init__
        self.setupUi(self)
        threading.Thread.__init__(self)
        self.VrepClass = CoppeliasimClass()
        self.jointhandles = []
        self.temp_path = temp_path  # 临时路径变量
####模块1
        self.Connect.clicked.connect(self.ConnectAll)
        self.Disconnect.clicked.connect(self.DisconnectAll)
        self.enable.clicked.connect(self.Enable)
        self.disable.clicked.connect(self.Disable)
####模块2
        self.movJ.clicked.connect(self.MoveJ)
        self.movL.clicked.connect(self.MoveL)
        self.movJ_3.clicked.connect(self.Jmove)
####模块3
        self.Define_button() 
####模块4
        self.smart_rob.clicked.connect(self.Smart_robot)
        self.handeye_cal.clicked.connect(self.Handeye_calibration)
####模块5
        self.gripper_0.clicked.connect(lambda: self.gripper_control(0))
        self.gripper_1.clicked.connect(lambda: self.gripper_control(1))
        self.clearerror.clicked.connect(self.Clearerror)
        self.speed.clicked.connect(self.Confirmspeed)
####模块6
        self.circledetect.clicked.connect(self.Detectcircle)
        self.boltdetect.clicked.connect(self.Detectbolt)
        self.save_img.clicked.connect(self.Saveimg)
        self.pointcloud.clicked.connect(self.Viewpointcloud)
        self.cam_info.clicked.connect(self.Caminfo)
        self.object_confirmation.clicked.connect(self.Object_detection)
####连接状态模块
    # 执行主要操作
    def ConnectAll(self):
        self.clientID = self.VrepClass.Connect('127.0.0.1', 19997)  # 连接Vrep
        if self.clientID != -1:
            self.VrepLabel.setStyleSheet('QLabel { background-color: rgb(0, 234, 0); }')  # Vrep指示灯亮
            self.LogText.append('Connect to Vrep')
            sim.simxStartSimulation(self.clientID, sim.simx_opmode_oneshot)  # 仿真初始化
            self.jointhandles = self.VrepClass.GetHandles(self.clientID, 6, 'UR5_joint')  # 得到六个关节角句柄
            self.ConnectRobot()
            if self.dashboard != False:
                self.VrepLabel_2.setStyleSheet('QLabel { background-color: rgb(0, 234, 0); }')  # robot指示灯亮
                self.LogText.append('Connect to Robot')
                self.dashboard.Tool(0)
                self.dashboard.CP(99)
                self.dashboard.SpeedFactor(20)  # 默认速度为20
                self.ReadTimer = QTimer()  # 实例化系统定时器, 用于机器人状态刷新
                self.ReadTimer.timeout.connect(self.ReadTask)  # 定时执行函数   #####self.ReadTask
                self.ReadTimer.start(5)  # 定时时间5ms

                self.cam = RealSenseThread()  # 实例化相机线程
                if self.cam.device_connected:
                    self.VrepLabel_3.setStyleSheet('QLabel{background-color: rgb(0, 234, 0)}')  # camera指示灯亮
                    self.LogText.append('Connect to camera')
                    # 初始化相机图像刷新定时器
                    self.camera_update_timer = QTimer()
                    self.camera_update_timer.timeout.connect(self.update_camera_display)
                    self.camera_update_timer.start(10)
                else:
                    self.LogText.append('Failed connect to Camera')
                    self.LogText.append("请检查相机是否连接")
            else:
                self.LogText.append(' Failed connect to Robot')
                self.LogText.append("请检查重试")
        else:
            self.LogText.append("Failed connect to Vrep")
            self.LogText.append("请检查重试")
    # 断联
    def DisconnectAll(self):
        try:
            self.dashboard.close()  # 关闭机械臂连接
            self.ReadTimer.stop()  # 定时器停止
            sim.simxFinish(-1)

            self.VrepLabel.setStyleSheet('')  # 指示灯灭
            self.VrepLabel_2.setStyleSheet('')  # 指示灯灭
            self.VrepLabel_3.setStyleSheet('')  # 指示灯灭

            self.camera_update_timer.stop()  # 相机定时器停止
            self.cam.stop()  # 停止相机线程
            cv2.destroyAllWindows()
            self.LogText.append('断开所有连接')
        except Exception as e:
            self.LogText.append(f'断开失败 {e}')
    # 机械臂使能
    # 机器人使能
    def Enable(self):
        print("开始使能...")
        try:
            self.dashboard.EnableRobot()  # enablerobot
            self.LogText.append('机器人使能成功')
        except Exception as e:
            self.LogText.append(f"使能失败 {e}")
    # 机器人失能
    def Disable(self):
        try:
            self.dashboard.DisableRobot()
            self.LogText.append('机器人下使能成功')
        except Exception as e:
            self.LogText.append(f'机器人失能失败 {e}')
    # 机器tcp连接函数
    def ConnectRobot(self):
        try:
            ip = "192.168.5.1"
            dashboardPort = 29999
            movePort = 30003
            feedPort = 30004
            print("正在建立连接...")
            self.dashboard = DobotApiDashboard(ip, dashboardPort)
            self.mover = DobotApiMove(ip, movePort)
            self.feed = DobotApi(ip, feedPort)
            self.dashboard.ClearError()  # 清除错误
            print(">.<连接成功>!<")
        except Exception as e:
            print(":(连接失败:(")
            raise e
####运动控制模块
    def MoveJ(self):
        # 笛卡尔空间运动，关节规划
        x = float(self.move_x.toPlainText())
        y = float(self.move_y.toPlainText())
        z = float(self.move_z.toPlainText())
        rx = float(self.move_rx.toPlainText())
        ry = float(self.move_ry.toPlainText())
        rz = float(self.move_rz.toPlainText())
        self.LogText.append('开始运动, 运动到坐标({:f},{:f},{:f},{:f},{:f},{:f})'.format(x,y,z,rx,ry,rz))
        self.mover.MovJ(x,y,z,rx,ry,rz)
        self.mover.Sync()
        self.LogText.append('笛卡尔空间运动完成')

    def MoveL(self):
        # 笛卡尔空间运动,走直线
        x = float(self.move_x.toPlainText())
        y = float(self.move_y.toPlainText())
        z = float(self.move_z.toPlainText())
        rx = float(self.move_rx.toPlainText())
        ry = float(self.move_ry.toPlainText())
        rz = float(self.move_rz.toPlainText())
        self.LogText.append('开始直线运动, 运动到坐标({:f},{:f},{:f},{:f},{:f},{:f})'.format(x,y,z,rx,ry,rz))
        self.mover.MovL(x,y,z,rx,ry,rz)
        self.mover.Sync()
        self.LogText.append('直线运动完成')

    def Jmove(self):
        # 关节空间运动
        j1 = float(self.move_j1.toPlainText())
        j2 = float(self.move_j2.toPlainText())
        j3 = float(self.move_j3.toPlainText())
        j4 = float(self.move_j4.toPlainText())
        j5 = float(self.move_j5.toPlainText())
        j6 = float(self.move_j6.toPlainText())
        self.LogText.append('开始运动, 运动到({:f},{:f},{:f},{:f},{:f},{:f})'.format(j1,j2,j3,j4,j5,j6))
        self.mover.JointMovJ(j1,j2,j3,j4,j5,j6)
        self.mover.Sync()
        self.LogText.append('关节空间运动完成')

####机器人状态模块功能
    def Define_button(self):
        LABEL_JOINT = [["J1-", "J2-", "J3-", "J4-", "J5-", "J6-"],
               ["J1+", "J2+", "J3+", "J4+", "J5+", "J6+"]]

        LABEL_COORD = [["X-", "Y-", "Z-", "Rx-", "Ry-", "Rz-"],
                    ["X+", "Y+", "Z+", "Rx+", "Ry+", "Rz+"]]
        # 关节按键控制
        # J1-J6 正向运动
        self.Jplus_7.pressed.connect(lambda: self.mover.MoveJog(LABEL_JOINT[1][0]))
        self.Jplus_9.pressed.connect(lambda: self.mover.MoveJog(LABEL_JOINT[1][1]))
        self.Jplus_11.pressed.connect(lambda: self.mover.MoveJog(LABEL_JOINT[1][2]))
        self.Jplus_13.pressed.connect(lambda: self.mover.MoveJog(LABEL_JOINT[1][3]))
        self.Jplus_15.pressed.connect(lambda: self.mover.MoveJog(LABEL_JOINT[1][4]))
        self.Jplus_17.pressed.connect(lambda: self.mover.MoveJog(LABEL_JOINT[1][5]))
        # J1-J6 负向运动
        self.Jplus_8.pressed.connect(lambda: self.mover.MoveJog(LABEL_JOINT[0][0]))
        self.Jplus_10.pressed.connect(lambda: self.mover.MoveJog(LABEL_JOINT[0][1]))
        self.Jplus_12.pressed.connect(lambda: self.mover.MoveJog(LABEL_JOINT[0][2]))
        self.Jplus_14.pressed.connect(lambda: self.mover.MoveJog(LABEL_JOINT[0][3]))
        self.Jplus_16.pressed.connect(lambda: self.mover.MoveJog(LABEL_JOINT[0][4]))
        self.Jplus_18.pressed.connect(lambda: self.mover.MoveJog(LABEL_JOINT[0][5]))
        # 所有按钮的释放事件连接到停止函数
        for btn in [self.Jplus_7, self.Jplus_9, self.Jplus_11, self.Jplus_13, self.Jplus_15, self.Jplus_17,
                self.Jplus_8, self.Jplus_10, self.Jplus_12, self.Jplus_14, self.Jplus_16, self.Jplus_18]:
            btn.released.connect(lambda: self.mover.MoveJog(""))
        # 笛卡尔按键控制
        # X+ Y+ Z+ Rx+ Ry+ Rz+
        self.Xplus.pressed.connect(lambda: self.mover.MoveJog(LABEL_COORD[1][0]))
        self.Xplus_3.pressed.connect(lambda: self.mover.MoveJog(LABEL_COORD[1][1]))
        self.Xplus_5.pressed.connect(lambda: self.mover.MoveJog(LABEL_COORD[1][2]))
        self.Xplus_7.pressed.connect(lambda: self.mover.MoveJog(LABEL_COORD[1][3]))
        self.Xplus_9.pressed.connect(lambda: self.mover.MoveJog(LABEL_COORD[1][4]))
        self.Xplus_11.pressed.connect(lambda: self.mover.MoveJog(LABEL_COORD[1][5]))
        # X- Y- Z- Rx- Ry- Rz-
        self.Xplus_2.pressed.connect(lambda: self.mover.MoveJog(LABEL_COORD[0][0]))
        self.Xplus_4.pressed.connect(lambda: self.mover.MoveJog(LABEL_COORD[0][1]))
        self.Xplus_6.pressed.connect(lambda: self.mover.MoveJog(LABEL_COORD[0][2]))
        self.Xplus_8.pressed.connect(lambda: self.mover.MoveJog(LABEL_COORD[0][3]))
        self.Xplus_10.pressed.connect(lambda: self.mover.MoveJog(LABEL_COORD[0][4]))
        self.Xplus_12.pressed.connect(lambda: self.mover.MoveJog(LABEL_COORD[0][5]))
        # 所有按钮的释放事件连接到停止函数
        for btn in [self.Xplus, self.Xplus_3, self.Xplus_5, self.Xplus_7, self.Xplus_9, self.Xplus_11,
                self.Xplus_2, self.Xplus_4, self.Xplus_6, self.Xplus_8, self.Xplus_10, self.Xplus_12]:
            btn.released.connect(lambda: self.mover.MoveJog(""))

    def ReadTask(self):
        # 读取数据
        pose=self.dashboard.GetPose()
        # 使用正则表达式提取第一个大括号内的数据
        cmatch = re.search(r'\{(.*?)\}', pose)
        if cmatch:
            zhengjie = cmatch.group(1)
            cpose = zhengjie.strip().split(',')
            # cpose=[format(num, '.3f') for num in cpose]
            self.Xtext.setText(cpose[0])
            self.Xtext_2.setText(cpose[1])
            self.Xtext_3.setText(cpose[2])
            self.Xtext_4.setText(cpose[3])
            self.Xtext_5.setText(cpose[4])
            self.Xtext_6.setText(cpose[5])

        angle=self.dashboard.GetAngle()
        # 使用正则表达式提取第一个大括号内的数据
        jmatch = re.search(r'\{(.*?)\}', angle)
        if jmatch:
            zheng = jmatch.group(1)
            jpose = zheng.strip().split(',')
            self.J1text.setText(jpose[0])
            self.J1text_2.setText(jpose[1])
            self.J1text_3.setText(jpose[2])
            self.J1text_4.setText(jpose[3])
            self.J1text_5.setText(jpose[4])
            self.J1text_6.setText(jpose[5])
            lastpose = np.array(list(map(float, jpose))) * np.pi / 180
            # 同步到Vrep
            for i in range(6):
                sim.simxSetJointTargetPosition(self.clientID,self.jointhandles[i],lastpose[i],sim.simx_opmode_blocking)
####高级功能模块 
    def Smart_robot(self):
        #打开一个新的页面
        #智能化机器人模块，可自主执行一定的抓取任务
        pass

    def Handeye_calibration(self):
        #打开一个新的页面
        #手眼标定模块，手动标定机器人与相机的相对位姿
        pass

####机器人控制模块
    # 夹爪动作控制
    def gripper_control(self,signal):
        if signal==0:
            self.dashboard.SetTerminal485(115200,8,"N",1) #设置485总线参数
            err= self.dashboard.ModbusCreate('127.0.0.1',60000,1,1)#建立连接
            id=1
            inBits = self.dashboard.GetHoldRegs(id,256,1,type="U16")#读初始化信息
            speed = self.dashboard.GetHoldRegs(id,260,1,type="U16")
            self.dashboard.SetHoldRegs(id, 259, 1, table=str(30))
            time.sleep(2)
            self.LogText.append('关闭夹爪')
        elif signal==1:
            self.dashboard.SetTerminal485(115200,8,"N",1) #设置485总线参数
            err= self.dashboard.ModbusCreate('127.0.0.1',60000,1,1)#建立连接
            id=1
            inBits = self.dashboard.GetHoldRegs(id,256,1,type="U16")#读初始化信息
            speed = self.dashboard.GetHoldRegs(id,260,1,type="U16")
            self.dashboard.SetHoldRegs(id, 259, 1, table=str(1000))
            time.sleep(2)
            self.LogText.append('打开夹爪')
        else :
            self.LogText.append('错误的夹取信号，请查看源代码')
    # 清除报警
    def Clearerror(self):
        self.dashboard.ClearError()
        self.LogText.append('清除机器人错误')
    # 速度确认
    def Confirmspeed(self):
        self.fullspeed = int(self.speedtext.toPlainText())
        self.dashboard.SpeedFactor(self.fullspeed)
        self.LogText.append(f'全局速度因子为：{str(self.fullspeed)}')

####相机功能模块
    def update_camera_display(self):
        try:
            # 获取相机图像
            color_frame, _ = self.cam.get_images()

            if color_frame is not None:
                rgb_image = cv2.cvtColor(color_frame, cv2.COLOR_BGR2RGB)
                height, width, channels = rgb_image.shape
                bytes_per_line = channels * width
                # 使用正确的QImage格式常量
                qt_image = QImage(rgb_image.data, width, height, bytes_per_line, QImage.Format.Format_RGB888)
                pixmap = QPixmap.fromImage(qt_image)
                # 修改 Qt 枚举值
                scaled_pixmap = pixmap.scaled(
                    self.show_img.size(), 
                    Qt.AspectRatioMode.KeepAspectRatio,
                    Qt.TransformationMode.SmoothTransformation
                )
                self.show_img.setPixmap(scaled_pixmap)
                # 强制更新显示
                self.show_img.update()
                QtWidgets.QApplication.processEvents()
        except Exception as e:
            self.LogText.append("相机图像更新错误:"+str(e))
            self.camera_update_timer.stop()

    def Detectcircle(self):
        """检测图像中的圆形或椭圆孔洞
            使用cv2方法识别"""
        image_path = os.path.join(self.temp_path, "color.png")
        if not image_path:
            self.ui.LogText.append("请先保存图像！！！")
            return
        image = cv2.imread(image_path)
        if image is None:
            self.ui.LogText.append("无法加载图像，请检查路径。")
            return
        try:
            self.LogText.append('正在使用OpenCV检测圆形或椭圆孔洞')
            # 形态学操作：去噪
            height, width = image.shape[:2]
            # gaussian_blur = cv2.GaussianBlur(image, (9, 9), 0)  # 第二个参数是滤波器的大小，第三个参数是标准差
            # sharpening_kernel = np.array([[-1, -1, -1],
            #                               [-1, 10, -1],
            #                               [-1, -1, -1]])
            # img0 = cv2.filter2D(gaussian_blur, -1, sharpening_kernel)

            kernel = np.ones((5, 5), np.uint8)
            morph_image = cv2.morphologyEx(image, cv2.MORPH_OPEN, kernel)
            # 转换为灰度图
            gray = cv2.cvtColor(morph_image, cv2.COLOR_BGR2GRAY)
            # 自适应阈值处理
            binary = cv2.adaptiveThreshold(gray, 255,
                                        cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
                                        cv2.THRESH_BINARY,
                                        11, 5)
            # Canny 边缘检测
            # edges = cv2.Canny(binary, 20, 200, apertureSize=3, L2gradient=True)
            edges = cv2.Canny(gray, 20, 200, apertureSize=3, L2gradient=True)
            # 查找轮廓
            contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
            valid_ellipses = []

            for contour in contours:
                area = cv2.contourArea(contour)
                arc_len = cv2.arcLength(contour, closed=True)

                # 筛选面积和长度
                if area < 80 or arc_len < 30:
                    continue
                # 拟合椭圆
                if len(contour) >= 8:  # 至少5个点才能拟合椭圆
                    try:
                        ellipse = cv2.fitEllipse(contour)
                        (x, y), (a, b), angle = ellipse
                        # 计算长宽比
                        ratio = a / b if a > b else b / a
                        # 圆形或椭圆筛选条件（可调）
                        if 1.0 <= ratio <= 2.0:
                            valid_ellipses.append(ellipse)
                    except Exception as e:
                        print(f"拟合椭圆失败：{e}")
                        continue
            # 绘制所有有效椭圆
            for idx, ellipse in enumerate(valid_ellipses):
                center = tuple(map(int, ellipse[0]))
                axes = tuple(map(int, ellipse[1]))
                angle = ellipse[2]
                color = (0, 255, 0)  # 绿色框
                thickness = 2

                # 绘制椭圆
                cv2.ellipse(image, center, axes, angle, 0, 360, color, thickness)

                # 添加编号标签
                label = f"{idx + 1}"
                font = cv2.FONT_HERSHEY_SIMPLEX
                font_scale = 0.6
                text_size, _ = cv2.getTextSize(label, font, font_scale, thickness)
                text_w, text_h = text_size

                # 标签背景
                cv2.rectangle(image, (center[0] - 10, center[1] - 25),
                            (center[0] - 10 + text_w + 5, center[1]), color, -1)
                # 标签文字
                cv2.putText(image, label, (center[0] - 8, center[1] - 8),
                            font, font_scale, (255, 255, 255), thickness)

            # 保存结果图像
            output_path =os.path.join(self.temp_path, "detected_circles_result.png")
            cv2.imwrite(output_path, image)
            self.LogText.append("已保存检测结果图像到 {}。".format(output_path))

            # 显示图像（使用 OpenCV 显示，也可以改为 QLabel 显示）
            cv2.imshow("Circle_detect", image)
            cv2.waitKey(2000)
            cv2.destroyAllWindows()
        except Exception as e:
            self.LogText.append("检测圆形或椭圆孔洞失败:"+str(e))

    # 识别螺栓
    def Detectbolt(self):
        """使用yolo训练的模型来识别螺栓"""
        import onnxruntime as rt
        # 识别螺栓
        height, width = 640, 640
        color_path = os.path.join(self.temp_path, 'color.png')
        if not os.path.exists(color_path):
            self.LogText.append("请先保存图像！！！")
            return
        try:
            self.LogText.append('正在使用YOLO模型识别螺栓')
            img0 = cv2.imread(color_path)
            # 定义锐化核
            # gaussian_blur = cv2.GaussianBlur(img0, (5, 5), 0)  # 第二个参数是滤波器的大小，第三个参数是标准差
            # sharpening_kernel = np.array([[-1, -1, -1],
            #                               [-1, 10, -1],
            #                              [-1, -1, -1]])
            # # 应用锐化核
            # img0 = cv2.filter2D(gaussian_blur, -1, sharpening_kernel)
            x_scale = img0.shape[1] / width
            y_scale = img0.shape[0] / height
            img = img0 / 255.
            img = cv2.resize(img, (width, height))
            img = np.transpose(img, (2, 0, 1))
            data = np.expand_dims(img, axis=0)
            sess = rt.InferenceSession("Dobot/visionm_1/best1.onnx")
            input_name = sess.get_inputs()[0].name
            label_name = sess.get_outputs()[0].name
            pred = sess.run([label_name], {input_name: data.astype(np.float32)})[0]
            pred = np.squeeze(pred)
            pred = np.transpose(pred, (1, 0))
            pred_class = pred[..., 4:]
            pred_conf = np.max(pred_class, axis=-1)
            pred = np.insert(pred, 4, pred_conf, axis=-1)
            result = model.nms(pred, 0.4, 0.3)
            self.LogText.append(f"识别结果：{result}")
            ret_img, _ = model.draw(img0, x_scale, y_scale, result)
            # ret_img = ret_img[:, :, ::-1] #颜色反转cv2使用BGR，相继获得是RGB
            cv2.imwrite(os.path.join(self.temp_path, "detected_bolts_result.png"), ret_img)
            self.LogText.append("已保存识别结果图像到 {}。".format(os.path.join(self.temp_path, "detected_bolts_result.png")))
            cv2.imshow("Bolt_detect",ret_img)
            cv2.waitKey(2000)
            cv2.destroyAllWindows()
        except Exception as e:
            self.LogText.append("识别螺栓失败:"+str(e))

    def Object_detection(self):
        """使用视觉大模型进行万物检测"""
        try:
            color_path = os.path.join(self.temp_path, 'color.png')
            if not os.path.exists(color_path):
                self.LogText.append("请先保存图像！！！")
                return
            self.LogText.append('正在进行万物检测')
            color_img = cv2.imread(color_path)
            _, buffer = cv2.imencode('.png', color_img)
            color_base64 = 'data:png;base64,' + base64.b64encode(buffer).decode('utf-8')

            object_name = self.object_recognition.toPlainText()
            self.LogText.append(f'正在识别"{object_name}"')
            # 调用OpenAI API进行文本生成
            client = openai.OpenAI(api_key=VLM_key_in_use,
                                base_url=VLM_base_url_in_use)
            self.LogText.append(f'正在调用{VLM_model_in_use}模型识别')
            # 向大模型发起请求
            completion = client.chat.completions.create(
                model=VLM_model_in_use,
                messages=[
                    {
                        "role": "user",
                        "content": [
                            {
                                "type": "text",
                                "text": f"find {object_name} on the table"+
                                " Please output in the following JSON format: "+
                        "{'name': [object_name1, object_name2, object_name3], 'id': [0, 1, 2], 'bbox': [[x_min1, y_min1, x_max1, y_max1], [x_min2, y_min2, x_max2, y_max2], ...]}."+
                        "Each 'bbox' entry corresponds to the bounding box of the respective object in the 'name' list."+
                        "Ensure that each object has a unique ID starting from 0 and incrementing by 1. No descriptions or extra information."+
                        "Example: {'name': ['block', 'chair', 'book'], 'id': [0, 1, 2], 'bbox': [[0, 0, 10, 10], [15, 15, 30, 30], [5, 5, 20, 20]]}"+
                        "Example: {'name': ['block', 'block', 'bolt', 'phone'], 'id': [0, 1, 2, 3], 'bbox': [[0, 0, 5, 5], [10, 10, 20, 20], [5, 5, 10, 10], [15, 15, 25, 25]]}"
                            },
                            {
                                "type": "image_url",
                                "image_url": {
                                    "url": color_base64
                                }
                            }
                        ]
                    },
                ]
            )
            # 解码生成的文本
            result = completion.choices[0].message.content.strip()
            result = result.replace("```","").replace("json","").replace("'",'"')
            self.LogText.append(f'Objects on the table:{result}')
            result = json.loads(result)
            def draw_bounding_boxes(id_image, bboxes, save_path=None, log_func=None):
                """
                在图像上为每个物体绘制不同颜色的边界框
                :param id_image: 原始图像 (numpy array)
                :param bboxes: 边界框列表，格式 [[x1, y1, x2, y2], ...]
                :param save_path: 保存路径（可选）
                :param log_func: 日志输出函数（可选）
                """
                if not bboxes:
                    if log_func:
                        log_func("未检测到任何物体。")
                    return id_image

                thickness = 1
                # 预定义颜色列表（BGR 格式），也可以随机生成
                colors = [
                    (255, 0, 0),    # 蓝色
                    (0, 255, 0),    # 绿色
                    (0, 0, 255),    # 红色
                    (255, 255, 0),  # 浅蓝
                    (255, 0, 255),  # 紫色
                    (0, 255, 255)   # 黄色
                ]

                for i, (x_min, y_min, x_max, y_max) in enumerate(bboxes):
                    # 获取颜色：循环使用颜色列表 or 每次随机生成
                    color = colors[i % len(colors)]  # 循环使用颜色
                    # 绘制边界框
                    cv2.rectangle(id_image, (x_min, y_min), (x_max, y_max), color, thickness)

                    # 可选：添加编号标签
                    label = f"{i + 1}"
                    font = cv2.FONT_HERSHEY_SIMPLEX
                    font_scale = 0.6
                    # 绘制文字
                    cv2.putText(id_image, label, (x_min + 2, y_min - 8), font, font_scale, (255, 255, 0), thickness)

                # 显示图像
                cv2.imshow("Detection Result", id_image)
                cv2.waitKey(2000)
                cv2.destroyAllWindows()
                # 保存图像（如果提供路径）
                if save_path:
                    cv2.imwrite(save_path, id_image)
                    if log_func:
                        log_func(f"图像已保存至 {save_path}")

            id_image=color_img.copy()
            bboxes = result.get("bbox", [])
            id_path = os.path.join(self.temp_path, 'object_detect.png')
            draw_bounding_boxes(id_image, bboxes, save_path=id_path, log_func=self.LogText.append)
        except Exception as e:
            self.LogText.append("万物检测失败:"+str(e))
    def Saveimg(self):
        # 保存图像
        color_img_path = os.path.join(self.temp_path, 'color.png')
        depth_img_path = os.path.join(self.temp_path, 'depth.png')
        pc_path = os.path.join(self.temp_path, 'pointcloud.ply')
        self.cam.save_images(color_filename=color_img_path, depth_filename=depth_img_path)
        self.cam.save_pointcloud_to_ply(filename=pc_path)
        self.LogText.append('图像保存成功.')
        self.LogText.append(f'颜色图路径: {color_img_path}.')
        self.LogText.append(f'深度图路径: {depth_img_path}.')
        self.LogText.append(f'点云路径: {pc_path}')

    def Viewpointcloud(self):
        """打开文件对话框，选择PLY文件"""
        options = QFileDialog.Option.DontUseNativeDialog
        file_name, _ = QFileDialog.getOpenFileName(
            self,
            "选择PLY点云文件",
            "",
            "PLY Files (*.ply);;All Files (*)",
            options=options
        )
        if file_name:
            """加载并显示点云"""
            self.LogText.append(f'加载点云文件: {file_name}')
            try:
                pcd = o3d.io.read_point_cloud(file_name)
                if not pcd.has_points():
                    raise ValueError("文件中没有有效的点数据。")

                self.LogText.append(f"成功加载点云：{file_name}")
                self.LogText.append(f"点数量: {len(pcd.points)}")
                # 使用 Open3D 可视化窗口显示点云
                o3d.visualization.draw_geometries([pcd], window_name="Pointcloud")
            except Exception as e:
                self.LogText.append(f"加载点云失败: {e}")

    def Caminfo(self):
        """显示相机信息"""
        if hasattr(self, 'cam') and self.cam.device_connected:
            dialog = CameraInfoDialog(self.cam, self)
            dialog.exec()
        else:
            self.LogText.append("相机未连接，请先连接相机。")

if __name__=='__main__':
    app = QtWidgets.QApplication(sys.argv)
    path = 'Dobot/temp'
    window = MyWindow(temp_path=path)
    window.show()
    sys.exit(app.exec())